package com.android.binderserverclient0

import android.app.AlarmManager
import android.app.PendingIntent
import android.content.ContentProvider
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.os.HandlerThread
import android.os.SystemClock
import android.util.Log
import android.view.View
import android.widget.Toast
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.intPreferencesKey
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.work.ArrayCreatingInputMerger
import androidx.work.BackoffPolicy
import androidx.work.Constraints
import androidx.work.CoroutineWorker
import androidx.work.Data
import androidx.work.ExistingWorkPolicy
import androidx.work.NetworkType
import androidx.work.OneTimeWorkRequest
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.PeriodicWorkRequest
import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.RxWorker
import androidx.work.WorkInfo
import androidx.work.WorkManager
import androidx.work.WorkRequest
import androidx.work.impl.model.Preference
import androidx.work.workDataOf
import binderipc.IPassValue
import binderipc.PassValueConstant
import binderipc.PassValueProxy
import binderipc.PassValueService
import binderipcremoteviews.TranscationRemoteViewsService
import com.android.binderserverclient0.buryingpoint.IOnClickListener
import com.android.binderserverclient0.buryingpoint.OnClickListenerImpl
import com.android.binderserverclient0.buryingpoint.OnClickListenerProxy
import com.android.binderserverclient0.databinding.ActivityMainBinding
import com.android.binderserverclient0.mmkv.BundleKeys
import com.android.binderserverclient0.mmkv.TestMMKV
import com.android.binderserverclient0.mvi.ConsumeOnceValue
import com.android.binderserverclient0.mvi.MviDispatcherKTX
import com.android.binderserverclient0.mvi.ViewStates
import com.android.binderserverclient0.mvi2.intent.MainIntent
import com.android.binderserverclient0.mvi2.network.NetworkUtils
import com.android.binderserverclient0.mvi2.state.MainState
import com.android.binderserverclient0.mvi2.viewmodel.MainViewModel
import com.android.binderserverclient0.mvi2.viewmodel.ViewModelFactory
import com.android.binderserverclient0.workmanager.CheckDiskProgressWorker
import com.android.binderserverclient0.workmanager.CheckSystemWorker
import com.android.binderserverclient0.workmanager.ContinuationCheck1
import com.android.binderserverclient0.workmanager.ContinuationCheck2
import com.android.binderserverclient0.workmanager.ContinuationCheck3
import com.android.binderserverclient0.workmanager.ContinuationCheck4
import com.android.binderserverclient0.workmanager.ContinuationCheck5
import com.android.binderserverclient0.workmanager.DefineWorker
import com.android.binderserverclient0.workmanager.DoChainWorker
import com.android.binderserverclient0.workmanager.DoWorker
import com.android.binderserverclient0.workmanager.FirstListenableWorker
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import java.util.Calendar
import java.util.concurrent.TimeUnit

class MainActivity : BaseActivity<ActivityMainBinding>() {

    private var passValue: IPassValue? = null

    private lateinit var mViewMode: MviDispatcherKTX<ViewStates>

    private lateinit var mMainViewModel: MainViewModel

    override fun getLayoutId() = R.layout.activity_main

    override fun init(savedInstanceState: Bundle?) {

        var contentProvider: ContentProvider? = null

        var mHandlerThread: HandlerThread? = null

        var mWorkManager: WorkManager? = null

        mViewMode = ViewModelProvider(this)[MviDispatcherKTX::class.java] as MviDispatcherKTX<ViewStates>

        mMainViewModel = ViewModelProvider(
            this,
            ViewModelFactory(NetworkUtils.apiService)
        )[MainViewModel::class.java]

//        val serviceIntent = Intent().apply {
//            `package` = "com.android.binderserverclient0"
//            setClassName("com.android.binderserverclient0", "com.android.binderserverclient0.service.PassValueService")
//        }
//
//        bindService(serviceIntent, object : ServiceConnection {
//            override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
//                passValue = PassValueService.asInterface(service)
//                //passValue = service?.queryLocalInterface(IPassValue.descriptor) as? IPassValue
//                Log.d(TAG,"value:${passValue?.passInt(5)}")
//            }
//            override fun onServiceDisconnected(name: ComponentName?) {
//                passValue = null
//            }
//        }, Context.BIND_AUTO_CREATE)

        //ContentProvider本身可以跨进程通信
//        val bundleResult = contentResolver.call(
//            Uri.parse(PassValueConstant.PASS_VALUE_URI),
//            PassValueConstant.ACTION_GET_SERVICE,
//            null,
//            null
//        )
//
//        if (bundleResult != null) {
//            val binder = bundleResult.getBinder(PassValueConstant.KEY_SERVER)
//            if (binder != null) {
//                val passValue = PassValueProxy(binder, cacheDir)
//                val instance = passValue.getProxyInstance() as? IPassValue
//                Log.d(TAG,"value:${instance?.passInt(5)}")
//            }
//        }

        //直接传值使用
//        val mPassValue = PassValueProxy(PassValueService(cacheDir), cacheDir)
//        val mInstance = mPassValue.getProxyInstance() as IPassValue?
//        Log.d(TAG,"value:${mInstance?.passInt(5)}")


        //注册服务获取服务使用
        mBinding.btnRegisterService.setOnClickListener {
            //注册PassValueService
            BinderIPCApplication.getBCServiceManager()?.addService("PassValueService", PassValueService(cacheDir))
            BinderIPCApplication.getBCServiceManager()?.addService("TranscationRemoteViewsService", TranscationRemoteViewsService(this@MainActivity))
        }

        mBinding.btnGetValue.setOnClickListener {
            val passValue = BinderIPCApplication.getBCServiceManager()?.getService("PassValueService")
                ?.let { PassValueProxy(it, cacheDir) }
            //Log.d(TAG,"value:${passValue?.passInt(5)}")
            Log.d(TAG, "value:${passValue?.passValueByOneWay(15, 20)}")
        }

        Log.d(TAG, "activity:${BinderIPCApplication.getBCServiceManager() != null}")
        Log.d(TAG, "activity:1234455")

        //HandlerThread本身是一个Thread,run()方法中使用了Looper.prepare()和Looper.loop()包裹代码块,
        //因此可以在子线中更新UI.重写onLooperPrepared()
        mBinding.btnUseHandlerThread.setOnClickListener {
            val mUseHandlerThread = object : HandlerThread("HandlerThread") {
                override fun onLooperPrepared() {
                    super.onLooperPrepared()
                    Thread.sleep(5000)
                    mBinding.btnRegisterService.text = "btnRegisterService"
                }
            }
            mUseHandlerThread.start()
        }

        mBinding.btnUseWorkManager.setOnClickListener {
            val constraints = Constraints
                .Builder()
                .setRequiresBatteryNotLow(true) //电量足够
                .setRequiredNetworkType(NetworkType.CONNECTED)//必须联网
                .build()
            val request001 = OneTimeWorkRequest
                .Builder(CheckSystemWorker::class.java)
                //传递数据
                //.setInputData(Data.Builder().apply {
                //    putString("haha0","001100")
                //    putInt("haha1", 123456)
                //}.build())
                //重试和回避策略
                //.setBackoffCriteria(BackoffPolicy.LINEAR, WorkRequest.MIN_BACKOFF_MILLIS, TimeUnit.MILLISECONDS)
                //设置约束
                //.setConstraints(constraints)
                //添加标识,并且可以通过标识取消请求
                //.addTag("network")
                //延时策略
                /*.setInitialDelay(3000, TimeUnit.SECONDS)*/.build()
            //监听数据变化
            WorkManager
                .getInstance(this@MainActivity)
                .getWorkInfoByIdLiveData(request001.id)
                .observe(this) {
                    if (WorkInfo.State.SUCCEEDED == it.state) {
                        //成功
                        for ((key, value) in it.outputData.keyValueMap) {
                            //获取数据

                        }
                    }
                }

            WorkManager.getInstance(this@MainActivity).enqueue(request001)
        }

        mBinding.btnUseWorkManager1.setOnClickListener {
            val workRequest =
                OneTimeWorkRequest.Builder(CheckDiskProgressWorker::class.java).build()

            WorkManager
                .getInstance(this@MainActivity)
                .getWorkInfoByIdLiveData(workRequest.id)
                .observe(this) {
                    when (it.state) {
                        WorkInfo.State.SUCCEEDED -> {
                            val progress = it.progress.getInt("progress", 100)
                            Log.d(TAG,"succeeded--progress:${progress}")
                        }
                        WorkInfo.State.RUNNING -> {
                            val progress = it.progress.getInt("progress", 0)
                            Log.d(TAG,"running--progress:${progress}")
                        }
                        WorkInfo.State.FAILED -> {

                        }
                        else -> {}
                    }
                }

            WorkManager.getInstance(this@MainActivity).enqueue(workRequest)
        }

        mBinding.btnUseWorkManager2.setOnClickListener {
            WorkManager
                .getInstance(this@MainActivity)
                .beginWith(OneTimeWorkRequest.Builder(ContinuationCheck1::class.java).also {
                    it.setInputData(workDataOf("name" to "Owen", "position" to "manager"))
                }.build())
                .then(OneTimeWorkRequest.Builder(ContinuationCheck2::class.java).build())
                .then(
                    listOf(
                        OneTimeWorkRequest.Builder(ContinuationCheck3::class.java).build(),
                        OneTimeWorkRequest.Builder(ContinuationCheck4::class.java).build()
                    )
                )
                .enqueue()
        }

        mBinding.btnUseWorkManager3.setOnClickListener {
            WorkManager
                .getInstance(this@MainActivity)
                .beginWith(OneTimeWorkRequest.Builder(ContinuationCheck1::class.java).also {
                    it.setInputData(workDataOf("name" to "Owen", "position" to "manager"))
                }.build())
                .then(OneTimeWorkRequest.Builder(ContinuationCheck2::class.java).build())
                .then(
                    listOf(
                        OneTimeWorkRequest.Builder(ContinuationCheck3::class.java).build(),
                        OneTimeWorkRequest.Builder(ContinuationCheck4::class.java).build()
                    )
                )
                .then(OneTimeWorkRequest.Builder(ContinuationCheck5::class.java).also {
                    //设置输入数据合并模式
                    it.setInputMerger(ArrayCreatingInputMerger::class.java)
                }.build())
                .enqueue()
        }

        mBinding.btnUseWorkManager4.setOnClickListener {
            val workRequest = PeriodicWorkRequestBuilder<CheckSystemWorker>(
                PeriodicWorkRequest.MIN_PERIODIC_FLEX_MILLIS,
                TimeUnit.MILLISECONDS
            ).build()
            //PeriodicWorkRequestBuilder重复性工作,用于定期执行某些动作.比如上传日志,备份数据.
            //无法使用连接功能,单个任务执行完了只会返回Result.success(),不会监听到State.SUCCEEDED状态.
            //其他的和OneTimeWorkRequest一样.
            WorkManager.getInstance(this@MainActivity).enqueue(workRequest)
        }

        mBinding.btnUseWorkManager5.setOnClickListener {
            //三种策略
            //ExistingWorkPolicy.REPLACE---取消删除替换
            //ExistingWorkPolicy.KEEP---保留,忽略新添加的.
            //ExistingWorkPolicy.APPEND---追加,逐一处理.
            WorkManager
                .getInstance(this@MainActivity)
                .enqueueUniqueWork(
                    "checkDisk",
                    ExistingWorkPolicy.APPEND,
                    OneTimeWorkRequest
                        .Builder(DoWorker::class.java)
                        .setInputData(workDataOf("uniqueWork" to "This is an uniqueWork"))
                        .build().also {
                            Log.d("DO_WORKER","${it.id} Check")
                        }
                )
        }

        mBinding.btnUseWorkManager6.setOnClickListener {
            //唯一任务工作链
            WorkManager
                .getInstance(this@MainActivity)
                .beginUniqueWork(
                    "check",
                    ExistingWorkPolicy.KEEP,
                    OneTimeWorkRequestBuilder<DoChainWorker>()
                        .setInputData(workDataOf(DoChainWorker.OP_KEY to DoChainWorker.OP_CHECK_NET))
                        .build()
                )
                .then(
                    OneTimeWorkRequestBuilder<DoChainWorker>()
                        .setInputData(workDataOf(DoChainWorker.OP_KEY to DoChainWorker.OP_CHECK_DISK))
                        .build()
                )
                .then(
                    OneTimeWorkRequestBuilder<DoChainWorker>()
                        .setInputData(workDataOf(DoChainWorker.OP_KEY to DoChainWorker.OP_CHECK_SYSTEM))
                        .build()
                )
                .enqueue()
        }

        //使用自定义Worker
        mBinding.btnUseWorkManager7.setOnClickListener {
            val workRequest = OneTimeWorkRequest.Builder(DefineWorker::class.java).build()
            WorkManager.getInstance(this@MainActivity).getWorkInfoByIdLiveData(workRequest.id).observe(this) {
                Log.d(TAG, "work state:${it.state}")
                if (WorkInfo.State.SUCCEEDED == it.state) {
                    for ((key, value) in it.outputData.keyValueMap) {
                        Log.d(TAG, "key:${key},value:${value}")
                    }
                }
            }
            WorkManager.getInstance(this@MainActivity).enqueue(workRequest)

            var mCoroutineWorker: CoroutineWorker? = null
            var mRxJavaWorker: RxWorker? = null
        }

        mBinding.btnAlarmManager1.setOnClickListener {
            val mAlarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
            val mIntent = Intent(this@MainActivity, AlarmReceiver::class.java)
            val mPendingIntent = PendingIntent.getBroadcast(
                this@MainActivity,
                0x01,
                mIntent,
                PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
            )

            //只执行一次,一分后后执行.
            mAlarmManager.set(
                AlarmManager.ELAPSED_REALTIME_WAKEUP,
                SystemClock.elapsedRealtime() + 60 * 1000,
                mPendingIntent
            )
        }

        mBinding.btnAlarmManager2.setOnClickListener {
            val mAlarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
            val mIntent = Intent(this@MainActivity, AlarmReceiver::class.java)
            val mPendingIntent = PendingIntent.getBroadcast(
                this@MainActivity,
                0x01,
                mIntent,
                PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
            )
            //重复执行,每隔30分钟执行一次.
            mAlarmManager.setInexactRepeating(
                AlarmManager.ELAPSED_REALTIME_WAKEUP,
                SystemClock.elapsedRealtime() + AlarmManager.INTERVAL_HALF_HOUR,
                 AlarmManager.INTERVAL_HALF_HOUR,
                mPendingIntent
            )
        }

        mBinding.btnAlarmManager3.setOnClickListener {
            val mAlarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager

            val mIntent = Intent(this@MainActivity, AlarmReceiver::class.java)
            val mPendingIntent = PendingIntent.getBroadcast(
                this@MainActivity,
                0x01,
                mIntent,
                PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
            )

            val mCalendar = Calendar.getInstance()
            mCalendar.timeInMillis = System.currentTimeMillis()
            mCalendar.set(Calendar.HOUR_OF_DAY, 14)

            //固定时间执行,每天下午两点执行.
            mAlarmManager.setInexactRepeating(
                AlarmManager.RTC_WAKEUP,
                mCalendar.timeInMillis,
                AlarmManager.INTERVAL_DAY,
                mPendingIntent
            )
        }

        mBinding.btnAlarmManager4.setOnClickListener {
            val mAlarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager

            val mIntent = Intent(this@MainActivity, AlarmReceiver::class.java)
            val mPendingIntent = PendingIntent.getBroadcast(
                this@MainActivity,
                0x01,
                mIntent,
                PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
            )

            val mCalendar = Calendar.getInstance()
            mCalendar.timeInMillis = System.currentTimeMillis()
            mCalendar.set(Calendar.HOUR_OF_DAY, 8)
            mCalendar.set(Calendar.MINUTE, 30)

            //固定时间执行,每天早上8:30执行,每隔20分钟执行一次.
            mAlarmManager.setRepeating(
                AlarmManager.RTC_WAKEUP,
                mCalendar.timeInMillis,
                20 * 60 * 1000,
                mPendingIntent
            )

            //取消
            mAlarmManager.cancel(mPendingIntent)
        }

        mBinding.btnBuryingPoint.setOnClickListener(clickInstance)

        output()
        mBinding.btnSingleDataFlow.setOnClickListener {
            input()
        }

        mBinding.btnSingleDataFlow2.setOnClickListener {
            lifecycleScope.launch {
                mMainViewModel.mainIntentChannel.send(MainIntent.GetWallPaper)

                mMainViewModel.outputState.collect {
                    when (it) {
                        is MainState.Idle -> {

                        }

                        is MainState.Loading -> {
                            Log.d(TAG, "MainState.Loading")
                        }

                        is MainState.GetWallPapers -> {
                            it.wallPaper.let { wallPaper ->
                                for (item in wallPaper.res.vertical) {
                                    Log.d(TAG, "item:${item.img}")
                                }
                            }
                        }

                        is MainState.Error -> {

                        }
                    }
                }
            }
        }

        //var sharedMemory: SharedMemory = SharedMemory.create("123", 1024 * 1024)

        //val pfds = ParcelFileDescriptor.createPipe()

        //val pfd = ParcelFileDescriptor.open(File(""), ParcelFileDescriptor.MODE_READ_ONLY)

        mBinding.btnMmkvUse.setOnClickListener {
            TestMMKV.getInstance().mmkv.encode(BundleKeys.TITLE, "123456")
            Log.d(TAG,"value0:${TestMMKV.getInstance().mmkv.decodeString(BundleKeys.TITLE,"no value")}")

            TestMMKV.getInstance().mmkv.encode(BundleKeys.FLAG, true)
            Log.d(TAG, "value1:${TestMMKV.getInstance().mmkv.decodeBool(BundleKeys.FLAG, false)}")

            //path:/data/user/0/com.android.binderserverclient0/files/mmkv
            Log.d(TAG, "value2:${this.filesDir.absolutePath}")
            Log.d(TAG, "value2:${this.externalCacheDir?.absolutePath}")

            TestMMKV.getInstance().mmkv.encode(BundleKeys.TEST_ENCODE0, 67890)
            Log.d(TAG, "value3:${TestMMKV.getInstance().mmkv.decodeInt(BundleKeys.TEST_ENCODE0)}")
        }

        mBinding.btnDataStore.setOnClickListener {
            launch {
                putV1("test", "7890", String::class.java)
            }

            launch {
                putV1("test011", 56789, Int::class.java)
            }

            launch {
                putV1("test2", "abcdefg", String::class.java)
            }

            launch {
                putV1("testStr2", 65432, Int::class.java)
            }

            launch {
                putV1("testInt", 1123, Int::class.java)
            }
        }

        mBinding.btnDataStore2.setOnClickListener {
            launch {
                getValueV1("test", String::class.java).collect {
                    Log.d(TAG, "dataStore1:test-${it as? String}")
                }
            }

            launch {
                getValueV1("test011", Int::class.java).collect {
                    Log.d(TAG, "dataStore1:test-${it as? Int}")
                }
            }

            launch {
                getValueV1("test2", String::class.java).collect {
                    Log.d(TAG, "dataStore1:test-${it as? String}")
                }
            }

            launch {
                getValueV1("testStr2", Int::class.java).collect {
                    Log.d(TAG, "dataStore1:test-${it as? Int}")
                }
            }

            launch {
                getValueV1("test0", Int::class.java).collect {
                    Log.d(TAG, "dataStore1:test0-${it as? Int}")
                }
            }
        }
    }

    private fun output() {
        mViewMode.output(this) {
            when (it) {
                is ViewStates.Download -> {
                    Log.d(TAG, "progress:${it.progress}")
                }
                is ViewStates.Info -> {

                }
                is ViewStates.Setting -> {

                }
                is ViewStates.List -> {

                }
            }
        }
    }

   private fun input() {
        launch {
            mViewMode.sendResult(ViewStates.Download(75))
        }
   }

    private val clickInstance by lazy {
        OnClickListenerImpl(object : OnClickListenerImpl.IClickCallback {
            override fun onClick(view: View?) {
                Log.d(TAG,"override fun onClick")

                //Toast.makeText(this@MainActivity, "点击item", Toast.LENGTH_SHORT).show()

                val proxy = OnClickListenerProxy(OnClickListenerImpl())
                val instance = proxy.getProxyInstance() as? IOnClickListener
                instance?.onClick(view)
            }
        })
    }

    companion object {
        const val TAG = "BinderServerClient0"
    }

}